package com.zdgk.core.control.forward.network.listener;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zdgk.core.control.config.ControlConfigInfo;
import com.zdgk.core.control.read.modbus.cache.DeviceRegisterCacheResult;
import com.zdgk.core.control.read.modbus.cache.entity.RuleValueEntity;
import com.zdgk.core.web.service.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.openmuc.j60870.ASdu;
import org.openmuc.j60870.ASduType;
import org.openmuc.j60870.CauseOfTransmission;
import org.openmuc.j60870.Connection;
import org.openmuc.j60870.ie.*;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SlaveAsduHandler {

    @Resource
    private ConfigService configService;
    private ControlConfigInfo controlConfigInfo;

    final private Integer SEND_COUNT = 16;
//    final private Integer DEVICE_IOA_MAX_COUNT = 71;
//    final private Integer DEVICE_IOA_SWITCH_MAX_COUNT = 26;

    private void sendCommonCommend(Connection connection, ASdu aSdu, CauseOfTransmission cause) throws IOException {
        ASdu response = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                cause,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                new InformationObject(0, new IeSingleCommand(false, 0, false))
        );
        connection.send(response);
    }

    public void HANDEL_C_IC_NA_1(Connection connection, ASdu aSdu) throws IOException {
        log.info("总召唤");
        controlConfigInfo = configService.getControlKey();
        String forwardMode = controlConfigInfo.getForwardMode104(); //ONE 分设备,TWO 汇总到一个设备，THREE 汇总以及额外IOA增加数值
        Integer threeAdd = controlConfigInfo.getThreeAdd104();
        Integer threeSwitchAdd = controlConfigInfo.getThreeSwitchAdd104();
        ASdu response = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.ACTIVATION_CON,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                new InformationObject[]{new InformationObject(0,
                        new InformationElement[][]{{new IeQualifierOfInterrogation(20)}})}
        );
        connection.send(response);
        switch (forwardMode) {
            case "ONE":
                HANDEL_C_IC_NA_1_ONE(connection, aSdu);
                break;
            case "TWO":
                HANDEL_C_IC_NA_1_TWO_THREE(connection, aSdu, 0, 0);
                break;
            case "THREE":
                HANDEL_C_IC_NA_1_TWO_THREE(connection, aSdu, threeAdd, threeSwitchAdd);
                break;
            default:
                break;
        }
        ASdu endResponse = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.ACTIVATION_TERMINATION,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                new InformationObject[]{new InformationObject(0,
                        new InformationElement[][]{{new IeQualifierOfInterrogation(20)}})}
        );
        connection.send(endResponse);
    }

    /**
     * 总召响应
     *
     * @param connection
     * @param aSdu
     * @throws IOException
     */
    public void HANDEL_C_IC_NA_1_ONE(Connection connection, ASdu aSdu) throws IOException {
        DeviceRegisterCacheResult.ruleValueMap.entrySet().forEach(e -> {
            Integer key = e.getKey();
            ArrayList<RuleValueEntity> value = e.getValue();
            List<RuleValueEntity> collect104 = value.stream().filter(x -> x.getAddress104() != null).collect(Collectors.toList());
            if (collect104.size() > 0) {
                int f = collect104.size() / SEND_COUNT;
                int y = collect104.size() % SEND_COUNT;
                for (int fi = 0; fi < f; fi++) {
                    InformationObject[] ioaGroup = new InformationObject[SEND_COUNT];
                    for (int i = 0; i < SEND_COUNT; i++) {
                        RuleValueEntity ruleValue = collect104.get(i + (SEND_COUNT * fi));
                        ioaGroup[i] = new InformationObject(
                                ruleValue.getAddress104(),
                                new IeShortFloat(ruleValue.getForwardValue()),
                                new IeQuality(false, false, false, false, false)
                        );
                    }
                    ASdu dataResponse = new ASdu(
                            ASduType.M_ME_NC_1,
                            aSdu.isSequenceOfElements(),
                            CauseOfTransmission.INTERROGATED_BY_STATION,
                            false,
                            false,
                            aSdu.getOriginatorAddress(),
                            key,
                            ioaGroup
                    );
                    try {
                        connection.send(dataResponse);
                    } catch (IOException ex) {

                    }
                }
                if (y > 0) {
                    InformationObject[] ioaGroup = new InformationObject[y];
                    for (int i = 0; i < y; i++) {
                        RuleValueEntity ruleValue = collect104.get(i + (SEND_COUNT * f));
                        ioaGroup[i] = new InformationObject(
                                ruleValue.getAddress104(),
                                new IeShortFloat(ruleValue.getForwardValue()),
                                new IeQuality(false, false, false, false, false)
                        );
                    }
                    ASdu dataResponse = new ASdu(
                            ASduType.M_ME_NC_1,
                            aSdu.isSequenceOfElements(),
                            CauseOfTransmission.INTERROGATED_BY_STATION,
                            false,
                            false,
                            aSdu.getOriginatorAddress(),
                            key,
                            ioaGroup
                    );
                    try {
                        connection.send(dataResponse);
                    } catch (IOException ex) {

                    }
                }
            }


        });
    }

    /**
     * 总召响应-合并
     *
     * @param connection
     * @param aSdu
     * @throws IOException
     */
    public void HANDEL_C_IC_NA_1_TWO_THREE(Connection connection, ASdu aSdu, Integer threeAdd, Integer threeSwitchAdd) throws IOException {
        int deviceIndex=0;
        Map<Integer, ArrayList<RuleValueEntity>> sortedMap = new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer k1, Integer k2) {
                return k1.compareTo(k2); // 升序排序
            }
        });
        sortedMap.putAll(DeviceRegisterCacheResult.ruleValueMap);
        for (Map.Entry<Integer, ArrayList<RuleValueEntity>> e : sortedMap.entrySet()) {
            Integer key = e.getKey();
            ArrayList<RuleValueEntity> value = e.getValue();
            switchSend(connection, aSdu, threeSwitchAdd, deviceIndex, value);
            analogSend(connection, aSdu, threeAdd, deviceIndex, value);
            deviceIndex++;
        }
    }

    private int computeAnalogCount(int index){
        int count = 0;
        for (int i = 0; i < index; i++) {
            count = count + controlConfigInfo.getServerPointCountArr()[i];
        }
        return count;
    }
    private int computeSwitchCount(int index){
        int count = 0;
        for (int i = 0; i < index; i++) {
            count = count + controlConfigInfo.getServerSwitchPointCountArr()[i];
        }
        return count;
    }
    /**
     * 发送单点类型值
     * @param connection
     * @param aSdu
     * @param threeAdd
     * @param deviceIndex
     * @param value
     */
    private void analogSend(Connection connection, ASdu aSdu, Integer threeAdd, int deviceIndex, ArrayList<RuleValueEntity> value) {
        List<RuleValueEntity> collect104 = value.stream().filter(x -> "analog".equals(x.getForwardType())).collect(Collectors.toList());
        if (collect104.size() > 0) {
            int nowSize = controlConfigInfo.getServerPointCountArr()[deviceIndex];
            int f = nowSize / SEND_COUNT;
            int y = nowSize % SEND_COUNT;
            for (int fi = 0; fi < f; fi++) {
                InformationObject[] ioaGroup = new InformationObject[SEND_COUNT];
                for (int i = 0; i < SEND_COUNT; i++) {
                    RuleValueEntity ruleValue = collect104.get(i + (SEND_COUNT * fi));
                    ioaGroup[i] = new InformationObject(
                            threeAdd + ruleValue.getAddress104() + computeAnalogCount(deviceIndex),
                            new IeShortFloat(ruleValue.getForwardValue()),
                            new IeQuality(false, false, false, false, false)
                    );
                }
                ASdu dataResponse = new ASdu(
                        ASduType.M_ME_NC_1,
                        aSdu.isSequenceOfElements(),
                        CauseOfTransmission.INTERROGATED_BY_STATION,
                        false,
                        false,
                        aSdu.getOriginatorAddress(),
                        1,
                        ioaGroup
                );
                try {
                    connection.send(dataResponse);
                } catch (IOException ex) {

                }
            }
            if (y > 0) {
                InformationObject[] ioaGroup = new InformationObject[y];
                for (int i = 0; i < y; i++) {
                    RuleValueEntity ruleValue = collect104.get(i + (SEND_COUNT * f));
                    ioaGroup[i] = new InformationObject(
                            threeAdd + ruleValue.getAddress104() +computeAnalogCount(deviceIndex),
                            new IeShortFloat(ruleValue.getForwardValue()),
                            new IeQuality(false, false, false, false, false)
                    );
                }
                ASdu dataResponse = new ASdu(
                        ASduType.M_ME_NC_1,
                        aSdu.isSequenceOfElements(),
                        CauseOfTransmission.INTERROGATED_BY_STATION,
                        false,
                        false,
                        aSdu.getOriginatorAddress(),
                        1,
                        ioaGroup
                );
                try {
                    connection.send(dataResponse);
                } catch (IOException ex) {

                }
            }
        }
    }
    public static JSONArray sortJsonArrayByAge(JSONArray jsonArray) {
        List<JSONObject> jsonList = new ArrayList<>();

        // 将 JSONArray 转换为 List<JSONObject>
        for (int i = 0; i < jsonArray.size(); i++) {
            jsonList.add(jsonArray.getJSONObject(i));
        }

        // 使用 Collections.sort() 方法进行排序
        Collections.sort(jsonList, new Comparator<JSONObject>() {
            @Override
            public int compare(JSONObject obj1, JSONObject obj2) {
                return Integer.compare(obj1.getInt("address"), obj2.getInt("address"));
            }
        });

        // 将排序后的 List<JSONObject> 转换回 JSONArray
        JSONArray sortedJsonArray = new JSONArray();
        for (JSONObject jsonObject : jsonList) {
            sortedJsonArray.put(jsonObject);
        }

        return sortedJsonArray;
    }
    private void switchSend(Connection connection, ASdu aSdu, Integer threeSwitchAdd, int deviceIndex, ArrayList<RuleValueEntity> value) {
        List<RuleValueEntity> collect104 = value.stream().filter(x -> "switch".equals(x.getForwardType())).collect(Collectors.toList());
        if (collect104.size() > 0) {
            for (int i = (collect104.size()-1); i >=0 ; i--) {
                RuleValueEntity ruleValueEntity = collect104.get(i);
                if ("split".equals(ruleValueEntity.getForwardMode())) {
                    try {
                        String addressInfo104 = ruleValueEntity.getAddressInfo104();
                        JSONArray jsonArray = JSONUtil.parseArray(addressInfo104);
                        jsonArray = sortJsonArrayByAge(jsonArray);
                        InformationObject[] ioaGroup = new InformationObject[jsonArray.size()];
                        for (int j = 0; j < jsonArray.size(); j++) {
                            JSONObject json = jsonArray.getJSONObject(j);
                            boolean on = false;
                            String tv = json.getStr("tv");
                            String [] tvs = tv.split(",");
                            for (int s = 0; s < tvs.length; s++) {
                                Float tvf = Float.valueOf(tvs[s]);
                                if(tvf.compareTo(ruleValueEntity.getForwardValue())==0){
                                    on = true;
                                }
                            }
                            ioaGroup[j] = new InformationObject(
                                    threeSwitchAdd + json.getInt("address") + computeSwitchCount(deviceIndex),
                                    new InformationElement[][]{
                                            {new IeSinglePointWithQuality(on, false, false, false, false)}}
                            );
                        }
                        ASdu dataResponse = new ASdu(
                                ASduType.M_SP_NA_1,
                                aSdu.isSequenceOfElements(),
                                CauseOfTransmission.INTERROGATED_BY_STATION,
                                false,
                                false,
                                aSdu.getOriginatorAddress(),
                                1,
                                ioaGroup
                        );
                        connection.send(dataResponse);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    //不处理
                }
            }
        }
    }

    /**
     * 计数量召唤
     *
     * @param connection
     * @param aSdu
     * @throws IOException
     */
    public void HANDEL_C_CI_NA_1(Connection connection, ASdu aSdu) throws IOException {
        ASdu response = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.ACTIVATION_CON,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                aSdu.getInformationObjects()
//                new InformationObject[] { new InformationObject(0,
//                        new InformationElement[][] { { new IeQualifierOfInterrogation(5) } }) }
        );
        connection.send(response);
        ASdu endResponse = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.ACTIVATION_TERMINATION,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                aSdu.getInformationObjects()
        );
        connection.send(endResponse);
    }


    /**
     * 时钟同步
     *
     * @param connection
     * @param aSdu
     * @throws IOException
     */
    public void HANDEL_C_CS_NA_1(Connection connection, ASdu aSdu) throws IOException {
        ASdu response = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.ACTIVATION_CON,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                new InformationObject[]{new InformationObject(0,
                        new InformationElement[][]{{new IeTime56(System.currentTimeMillis())}})}
        );
        connection.send(response);
    }

    /**
     * 读数据响应
     *
     * @param connection
     * @param aSdu
     * @throws IOException
     */
    public void HANDEL_C_RD_NA_1(Connection connection, ASdu aSdu) throws IOException {
        InformationObject[] informationObjects = aSdu.getInformationObjects();
        List<RuleValueEntity> collect104 = DeviceRegisterCacheResult.ruleValueMap.get(aSdu.getCommonAddress()).stream().filter(x -> x.getAddress104() != null && NumberUtil.equals(x.getAddress104(), informationObjects[0].getInformationObjectAddress())).collect(Collectors.toList());
        InformationObject[] ioaGroup = new InformationObject[1];
        if (collect104.size() == 1) {
            RuleValueEntity ruleValue = collect104.get(0);
            ioaGroup[0] = new InformationObject(
                    ruleValue.getAddress104(),
                    new IeShortFloat(ruleValue.getForwardValue()),
                    new IeQuality(false, false, false, false, false)
            );
        }
        ASdu dataResponse = new ASdu(
                ASduType.M_SP_NA_1,
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.INTERROGATED_BY_STATION,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                ioaGroup
        );
        connection.send(dataResponse);
    }

    /**
     * 单点响应
     *
     * @param connection
     * @param aSdu
     * @throws IOException
     */
    public void HANDEL_C_SC_NA_1(Connection connection, ASdu aSdu) throws IOException {
        ASdu response = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.ACTIVATION_CON,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                aSdu.getInformationObjects()
        );
        connection.send(response);
        ASdu endResponse = new ASdu(
                aSdu.getTypeIdentification(),
                aSdu.isSequenceOfElements(),
                CauseOfTransmission.ACTIVATION_TERMINATION,
                false,
                false,
                aSdu.getOriginatorAddress(),
                aSdu.getCommonAddress(),
                aSdu.getInformationObjects()
        );
        connection.send(endResponse);
    }
}
